﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using ZXing;
using ZXing.QrCode;
using ZXing.SkiaSharp;
using ZXing.SkiaSharp.Rendering;
using SkiaSharp;
using System.Windows.Media;
using System.ComponentModel;
using System.Net;
using ZXing.Common;
using ZXing.QrCode.Internal;
using AForge.Video;
using AForge.Video.DirectShow;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Text;

namespace 批量二维码生成与摄像头识别
{
    public partial class MainWindow : Window
    {
        /// <summary>
        /// 存储生成的二维码图片的输出文件夹路径
        /// </summary>
        /// 默认路径是"我的文档"下的"QR Codes"子文件夹
        private string _outputFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "QR Codes");

        /// <summary>
        /// 视频设备集合，用于存储系统中可用的摄像头设备
        /// </summary>
        private FilterInfoCollection _videoDevices;

        /// <summary>
        /// 视频捕获设备对象，用于从摄像头获取视频流
        /// </summary>
        private VideoCaptureDevice _videoSource;

        /// <summary>
        /// 标志位，表示当前是否正在扫描二维码
        /// </summary>
        private bool _isScanning = false;

        /// <summary>
        /// 二维码/条形码读取器实例，用于解析摄像头捕获的图像中的二维码
        /// </summary>
        private BarcodeReader _barcodeReader;

        /// <summary>
        /// 当前选择的摄像头索引，用于在多摄像头设备中切换摄像头
        /// </summary>
        private int _currentCameraIndex = 0;

        /// <summary>
        /// 标志位，表示当前使用的是前置摄像头还是后置摄像头
        /// </summary>
        /// 主要用于移动设备或具有前后摄像头的设备
        private bool _isFrontCamera = false;

        /// <summary>
        /// 存储已经扫描过的二维码内容，避免重复添加
        /// </summary>
        private HashSet<string> _scannedQrCodes = new HashSet<string>();

        public MainWindow()
        {
            InitializeComponent();
            txtOutputFolder.Text = $"二维码将保存到: {_outputFolder}";

            // 确保输出目录存在
            if (!Directory.Exists(_outputFolder))
            {
                Directory.CreateDirectory(_outputFolder);
            }

            // 初始化摄像头设备
            InitializeCameraDevices();

            // 初始化二维码阅读器
            _barcodeReader = new BarcodeReader
            {
                Options = new DecodingOptions
                {
                    TryHarder = true,
                    PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }
                }
            };
        }

        #region 摄像头相关方法

        /// <summary>
        /// 初始化摄像头设备
        /// </summary>
        private void InitializeCameraDevices()
        {
            _videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            if (_videoDevices.Count == 0)
            {
                MessageBox.Show("未检测到摄像头设备");
                return;
            }

            cboCameras.Items.Clear();
            foreach (FilterInfo device in _videoDevices)
            {
                cboCameras.Items.Add(device.Name);
            }

            // 默认选择后置摄像头
            _currentCameraIndex = FindRearCameraIndex();

            cboCameras.SelectedIndex = _currentCameraIndex;
        }

        /// <summary>
        /// 查找后置摄像头
        /// </summary>
        /// <returns></returns>
        private int FindRearCameraIndex()
        {
            for (int i = 0; i < _videoDevices.Count; i++)
            {
                var deviceName = _videoDevices[i].Name.ToLower();
                // 根据常见设备名称判断后置摄像头
                if (deviceName.Contains("rear") || deviceName.Contains("back") || deviceName.Contains("primary") || deviceName.Contains("main"))
                {
                    return i;
                }
            }
            // 如果没有明确的后置摄像头，默认选择第一个
            return 0;
        }

        /// <summary>
        /// 像头切换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SwitchCamera_Click(object sender, RoutedEventArgs e)
        {
            if (_isScanning)
            {
                MessageBox.Show("请先停止扫描再切换摄像头");
                return;
            }

            if (_videoDevices == null || _videoDevices.Count < 2)
            {
                MessageBox.Show("需要至少两个摄像头才能切换");
                return;
            }
            // 停止当前摄像头
            if (_videoSource != null && _videoSource.IsRunning)
            {
                _videoSource.SignalToStop();
                _videoSource.WaitForStop();
                _videoSource.NewFrame -= VideoSource_NewFrame;
                _videoSource = null;
            }
            // 切换摄像头
            _isFrontCamera = !_isFrontCamera;

            if (_isFrontCamera)
            {
                // 查找前置摄像头
                for (int i = 0; i < _videoDevices.Count; i++)
                {
                    var deviceName = _videoDevices[i].Name.ToLower();
                    if (deviceName.Contains("front") || deviceName.Contains("face"))
                    {
                        _currentCameraIndex = i;
                        break;
                    }
                }
            }
            else
            {
                // 使用后置摄像头
                _currentCameraIndex = FindRearCameraIndex();
            }
            cboCameras.SelectedIndex = _currentCameraIndex;

            StartCameraScan();
        }

        /// <summary>
        /// 启动摄像头
        /// </summary>
        private void StartCameraScan()
        {
            try
            {
                _isScanning = true;
                txtCameraResult.Text = "正在识别...";
                // 创建视频源
                var device = _videoDevices[_currentCameraIndex];
                _videoSource = new VideoCaptureDevice(device.MonikerString);
                _videoSource.NewFrame += VideoSource_NewFrame;
                _videoSource.Start();
                // 更新UI
                btnStartCamera.IsEnabled = false;
                btnStopCamera.IsEnabled = true;
                btnSwitchCamera.IsEnabled = false;
            }
            catch (Exception ex)
            {
                _isScanning = false;
                MessageBox.Show($"启动摄像头失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 开始识别
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartCameraScan_Click(object sender, RoutedEventArgs e)
        {
            if (_videoDevices == null || _videoDevices.Count == 0)
            {
                MessageBox.Show("没有可用的摄像头设备");
                return;
            }

            if (_isScanning) return;

            StartCameraScan();
        }

        /// <summary>
        /// 停止识别
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StopCameraScan_Click(object sender, RoutedEventArgs e)
        {
            if (!_isScanning) return;

            try
            {
                _isScanning = false;
                _scannedQrCodes.Clear(); // 清空已扫描记录

                if (_videoSource != null && _videoSource.IsRunning)
                {
                    _videoSource.SignalToStop();
                    _videoSource.WaitForStop();
                    _videoSource.NewFrame -= VideoSource_NewFrame;
                    _videoSource = null;
                }

                // 更新UI
                btnStartCamera.IsEnabled = true;
                btnStopCamera.IsEnabled = false;
                btnSwitchCamera.IsEnabled = true;
                txtCameraResult.Text = "已停止";

                // 在UI线程上更新预览图像
                Dispatcher.Invoke(() =>
                {
                    imgCameraPreview.Source = null;
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show($"停止摄像头失败: {ex.Message}");
            }
        }

        private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            try
            {
                // 获取当前帧
                var frame = (Bitmap)eventArgs.Frame.Clone();

                // 在UI线程上更新预览图像
                Dispatcher.Invoke(() =>
                {
                    imgCameraPreview.Source = ConvertBitmapToImageSource(frame);
                });

                // 将System.Drawing.Bitmap转换为SKBitmap
                using (var memoryStream = new MemoryStream())
                {
                    frame.Save(memoryStream,ImageFormat.Png);
                    memoryStream.Position = 0;
                    var skBitmap = SKBitmap.Decode(memoryStream);

                    // 识别二维码
                    var result = _barcodeReader.Decode(skBitmap);
                    if (result != null && !string.IsNullOrWhiteSpace(result.Text))
                    {
                        // 检查是否已经扫描过这个二维码
                        if (!_scannedQrCodes.Contains(result.Text))
                        {
                            _scannedQrCodes.Add(result.Text);

                            Dispatcher.Invoke(() =>
                            {
                                txtCameraResult.Text = result.Text;

                                // 添加到结果列表
                                var currentResults = qrCodeResultsGrid.ItemsSource as List<QrCodeResult> ?? new List<QrCodeResult>();
                                currentResults.Add(new QrCodeResult
                                {
                                    FileName = $"摄像头捕获_{DateTime.Now.ToString("yyyyMMddHHmmss")}.png",
                                    Content = result.Text
                                });
                                qrCodeResultsGrid.ItemsSource = currentResults;
                                qrCodeResultsGrid.Items.Refresh();
                            });
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"处理摄像头帧时出错: {ex.Message}");
            }
        }

        private ImageSource ConvertBitmapToImageSource(Bitmap bitmap)
        {
            using (var memory = new MemoryStream())
            {
                bitmap.Save(memory, ImageFormat.Bmp);
                memory.Position = 0;
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = memory;
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.EndInit();
                return bitmapImage;
            }
        }

        /// <summary>
        /// 关闭软件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
            StopCameraScan_Click(null, null);
        }

        #endregion

        #region 生成二维码相关方法

        /// <summary>
        /// 选择保存位置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SelectOutputFolder_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new Microsoft.Win32.OpenFileDialog
            {
                Title = "选择二维码保存位置",
                InitialDirectory = _outputFolder,
                ValidateNames = false,
                CheckFileExists = false,
                CheckPathExists = true,
                FileName = "选择文件夹"
            };

            if (dialog.ShowDialog() == true)
            {
                _outputFolder = Path.GetDirectoryName(dialog.FileName);
                txtOutputFolder.Text = $"二维码将保存到: {_outputFolder}";
            }
        }

        /// <summary>
        /// 生成单个二维码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GenerateQrCode_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtInput.Text))
            {
                MessageBox.Show("请输入要生成二维码的内容");
                return;
            }

            var content = txtInput.Text;
            var bitmap = GenerateQrCode(content);

            if (bitmap != null)
            {
                // 清空预览并添加新的二维码
                qrCodePreviewItems.Items.Clear();
                qrCodePreviewItems.Items.Add(new QrCodePreviewItem
                {
                    Image = SKBitmapToImageSource(bitmap),
                    Content = content
                });

                // 自动保存
                SaveQrCode(bitmap, content);
            }
        }

        /// <summary>
        /// 生成批量二维码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GenerateBatchQrCodes_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtInput.Text))
            {
                MessageBox.Show("请输入要生成二维码的内容");
                return;
            }

            var contents = txtInput.Text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            if (contents.Length == 0)
            {
                MessageBox.Show("没有有效的输入内容");
                return;
            }

            // 清空预览
            qrCodePreviewItems.Items.Clear();

            var previewItems = new List<QrCodePreviewItem>();

            foreach (var content in contents)
            {
                if (string.IsNullOrWhiteSpace(content)) continue;

                var bitmap = GenerateQrCode(content);
                if (bitmap != null)
                {
                    previewItems.Add(new QrCodePreviewItem
                    {
                        Image = SKBitmapToImageSource(bitmap),
                        Content = content
                    });

                    // 保存二维码
                    SaveQrCode(bitmap, content);
                }
            }

            // 添加预览项
            foreach (var item in previewItems)
            {
                qrCodePreviewItems.Items.Add(item);
            }

            MessageBox.Show($"已成功生成 {previewItems.Count} 个二维码");
        }

        /// <summary>
        /// 生成二维码
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        private SKBitmap GenerateQrCode(string content)
        {
            try
            {
                var options = new QrCodeEncodingOptions
                {
                    Width = 300,
                    Height = 300,
                    Margin = 1,
                    CharacterSet = "UTF-8",
                    Hints =
                    {
                        { EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H }
                    }
                };

                var writer = new BarcodeWriter<SKBitmap>
                {
                    Format = BarcodeFormat.QR_CODE,
                    Options = options,
                    Renderer = new SKBitmapRenderer()
                };

                return writer.Write(content);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"生成二维码时出错: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 保存二维码
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="content"></param>
        private void SaveQrCode(SKBitmap bitmap, string content)
        {
            try
            {
                // 生成安全的文件名
                var fileName = GenerateSafeFileName(content) + ".png";
                var filePath = Path.Combine(_outputFolder, fileName);

                using var image = SKImage.FromBitmap(bitmap);
                using var data = image.Encode(SKEncodedImageFormat.Png, 100);
                using var stream = File.OpenWrite(filePath);
                data.SaveTo(stream);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存二维码时出错: {ex.Message}");
            }
        }

        private string GenerateSafeFileName(string input)
        {
            var invalidChars = Path.GetInvalidFileNameChars();
            var safeName = new string(input
                .Where(c => !invalidChars.Contains(c))
                .ToArray());

            // 限制长度
            return safeName.Length > 50 ? safeName.Substring(0, 50) : safeName;
        }

        public static ImageSource SKBitmapToImageSource(SKBitmap skBitmap)
        {
            using (SKImage skImage = SKImage.FromBitmap(skBitmap))
            {
                SKPixmap skPixmap = skImage.PeekPixels();

                WriteableBitmap writeableBitmap = new WriteableBitmap(
                    skPixmap.Width,
                    skPixmap.Height,
                    96, 96,
                    PixelFormats.Pbgra32,
                    null);

                writeableBitmap.Lock();
                skPixmap.ReadPixels(new SKImageInfo(writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, SKColorType.Bgra8888),
                                   writeableBitmap.BackBuffer, writeableBitmap.BackBufferStride);
                writeableBitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight));
                writeableBitmap.Unlock();

                return writeableBitmap;
            }
        }

        #endregion

        #region 识别二维码相关方法

        private void DecodeQrCode_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Filter = "Image Files|*.png;*.jpg;*.jpeg;*.bmp;*.gif",
                Title = "选择图片",
                Multiselect = true
            };

            if (openFileDialog.ShowDialog() == true)
            {
                var results = new List<QrCodeResult>();

                foreach (var filePath in openFileDialog.FileNames)
                {
                    var result = DecodeQrCodeFromFile(filePath);
                    if (result != null)
                    {
                        results.Add(result);
                    }
                }

                DisplayResults(results);
            }
        }

        private void DecodeBatchQrCodes_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new OpenFileDialog
            {
                Title = "选择包含二维码图片的文件夹",
                Filter = "图片文件|*.png;*.jpg;*.jpeg;*.bmp;*.gif",
                Multiselect = true,
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
                ValidateNames = false,
                CheckFileExists = false,
                CheckPathExists = true,
                FileName = "选择文件夹"
            };

            // 这个技巧可以让用户选择文件夹而不是文件
            if (dialog.ShowDialog() == true)
            {
                string folderPath = Path.GetDirectoryName(dialog.FileName);

                var imageFiles = Directory.GetFiles(folderPath, "*.*", SearchOption.TopDirectoryOnly)
                    .Where(f => f.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
                                f.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
                                f.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
                                f.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ||
                                f.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))
                    .ToList();

                if (!imageFiles.Any())
                {
                    MessageBox.Show("所选文件夹中没有找到支持的图片文件");
                    return;
                }

                var results = new List<QrCodeResult>();

                foreach (var filePath in imageFiles)
                {
                    var result = DecodeQrCodeFromFile(filePath);
                    if (result != null)
                    {
                        results.Add(result);
                    }
                }

                DisplayResults(results);
            }
        }

        private QrCodeResult DecodeQrCodeFromFile(string filePath)
        {
            try
            {
                using (var stream = File.OpenRead(filePath))
                {
                    var bitmap = SKBitmap.Decode(stream);
                    if (bitmap == null)
                    {
                        return null;
                    }

                    var reader = new BarcodeReader
                    {
                        Options = new DecodingOptions
                        {
                            TryHarder = true,
                            PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }
                        }
                    };

                    var result = reader.Decode(bitmap);
                    return new QrCodeResult
                    {
                        FileName = Path.GetFileName(filePath),
                        Content = result?.Text ?? "未能识别二维码内容"
                    };
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"识别二维码时出错: {ex.Message}");
                return new QrCodeResult
                {
                    FileName = Path.GetFileName(filePath),
                    Content = $"识别出错: {ex.Message}"
                };
            }
        }

        private void DisplayResults(List<QrCodeResult> results)
        {
            qrCodeResultsGrid.ItemsSource = results;

            if (results.Any(r => r.Content.StartsWith("识别出错")))
            {
                MessageBox.Show($"已识别 {results.Count(r => !r.Content.StartsWith("识别出错"))} 个二维码，有 {results.Count(r => r.Content.StartsWith("识别出错"))} 个识别失败");
            }
            else
            {
                MessageBox.Show($"成功识别 {results.Count} 个二维码");
            }
        }

        #endregion

        private void SaveResultsToTxt_Click(object sender, RoutedEventArgs e)
        {
            var results = qrCodeResultsGrid.ItemsSource as List<QrCodeResult>;
            if (results == null || !results.Any())
            {
                MessageBox.Show("没有可保存的结果", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            SaveResultsToTxt(results);
        }


        private void SaveResultsToTxt(List<QrCodeResult> results)
        {
            try
            {
                var saveFileDialog = new SaveFileDialog
                {
                    Filter = "文本文件|*.txt",
                    Title = "保存识别结果",
                    FileName = "QRCodeResults_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt",
                    InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
                };

                if (saveFileDialog.ShowDialog() == true)
                {
                    using (StreamWriter writer = new StreamWriter(saveFileDialog.FileName, false, Encoding.UTF8))
                    {
                        writer.WriteLine("文件名\t二维码内容");
                        writer.WriteLine("----------------------------------------");

                        foreach (var result in results)
                        {
                            writer.WriteLine($"{result.FileName}\t{result.Content}");
                        }
                    }

                    MessageBox.Show($"结果已保存到: {saveFileDialog.FileName}", "保存成功", MessageBoxButton.OK, MessageBoxImage.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存结果时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

    }

    #region 数据模型类

    /// <summary>
    /// 二维码预览
    /// </summary>
    public class QrCodePreviewItem
    {
        /// <summary>
        /// 图片
        /// </summary>
        public ImageSource Image { get; set; }

        /// <summary>
        /// 内容
        /// </summary>
        public string Content { get; set; }
    }

    /// <summary>
    /// 二维码结果
    /// </summary>
    public class QrCodeResult
    {
        /// <summary>
        /// 文件名
        /// </summary>
        public string FileName { get; set; }

        /// <summary>
        /// 内容
        /// </summary>
        public string Content { get; set; }
    }

    #endregion
}